//
//  XIGame.m
//  XI Engine
//
//  Created by Balazs Faludi on 25.05.09.
//  Copyright 2009 Balazs Faludi. All rights reserved.
//

#import "XIGame.h"
#import "XIEngine.h".
#import "GTMObjectSingleton.h"
#import "EAGLView.h"
//#import "XIEnvironment.h"

@implementation XIGame

@synthesize targetFPS, targetSPF, currentFPS;
@synthesize activeScene;
@synthesize paused;
@synthesize multiplier;
@synthesize delegate;
@synthesize lastUpdate;
@synthesize renderView;

#pragma mark -
#pragma mark Singleton definition

GTMOBJECT_SINGLETON_BOILERPLATE(XIGame, sharedGame);

#pragma mark -
#pragma mark Constructor and destructor

- (id)init {
    if ((self = [super init])) {
		multiplier = 0.0;
		delegate = nil;
		targetFPS = kXIGameTargetFPSDefault;
		targetSPF = 1.0 / targetFPS;
		currentFPS = targetFPS;
		renderView = nil;
		paused = YES;
		_fpsSample = [[NSMutableArray alloc] initWithCapacity:30];
		_fpsLastUpdate = [[NSDate date] retain];
		_fpsFont = [[XIFont alloc] initWithFontDef:@"FontDenmark24.fnt" withTexture:@"FontDenmark24"];
		[self setupChipmunk];
    }
    return self;
}

- (void)dealloc {
	[self stopUpdating];
	[lastUpdate release];
    [activeScene release];
	[delegate release];
	[renderView release];
	[_updateTimer release];
	[_fpsSample release];
	[_fpsLastUpdate release];
    [super dealloc];
}


#pragma mark -
#pragma mark Loop

- (void)updateFPS
{
	NSTimeInterval interval = -[lastUpdate timeIntervalSinceNow];
	int fps = (int)round(1.0/interval);
	[_fpsSample addObject:[NSNumber numberWithInt:fps]];
	if([_fpsSample count] > 20){[_fpsSample removeObjectAtIndex:0];}
	if(-[_fpsLastUpdate timeIntervalSinceNow] > kXIFPSUpdateInterval)
	{
		float average = 0;
		for(NSNumber *number in _fpsSample){average += [number intValue];}
		average /= [_fpsSample count];
		currentFPS = (int)round(average);
		if(_fpsLastUpdate){[_fpsLastUpdate release];}
		_fpsLastUpdate = [[NSDate date] retain];
	}
}

- (void)drawFPS
{
	NSString *str = [NSString stringWithFormat:@"%i", (int)round(currentFPS)];
	[_fpsFont renderString:str inRect:CGRectMake(30.0, 10.0, 40.0, 40.0)];
}

- (void)update
{
	NSTimeInterval interval = lastUpdate ? [lastUpdate timeIntervalSinceNow] : 0.0;
	multiplier = interval * targetFPS;
	
	if(!paused || activeScene.ignoresPause)
	{
		[activeScene update];
	}
}

- (void)draw
{
	[renderView prepareForNewFrame];
	[activeScene draw];
#if kXIShowFPS
	[self drawFPS];
#endif
	[renderView finalizeFrame];
}

- (void)needsUpdate
{
	[self update];
	//[_glView drawView];
#ifdef kXIShowFPS
	[self updateFPS];
#endif
	//[_glView updateFPS];
	if(lastUpdate){[lastUpdate release];}
	lastUpdate = [[NSDate date] retain];
	[self draw];
}

- (void)startUpdating
{
	if(_updateTimer){[_updateTimer invalidate];}
	_updateTimer = [NSTimer scheduledTimerWithTimeInterval:targetSPF target:self selector:@selector(needsUpdate) userInfo:nil repeats:YES];
}

- (void)stopUpdating
{
	[_updateTimer invalidate];
	//self._updateTimer = nil;
}

- (void)set_updateTimer:(NSTimer *)newTimer {
    [_updateTimer invalidate];
    _updateTimer = newTimer;
}

#pragma mark -
#pragma mark Public methods

- (void)start
{
	self.paused = NO;
}

- (void)setPaused:(BOOL)newPaused
{
	//if(paused = newPaused){return;}
	paused = newPaused;
	if(paused){[self stopUpdating];}
	else{[self startUpdating];}
}

- (void)setTargetFPS:(float)newTargetFPS {
    
    targetFPS = newTargetFPS;
	targetSPF = 1.0 / newTargetFPS;
    if (_updateTimer) {
        [self stopUpdating];
        [self startUpdating];
    }
}

- (void)setTargetSPF:(float)newTargetSPF {
    
    targetSPF = newTargetSPF;
	targetFPS = 1.0 / targetSPF;
    if (_updateTimer) {
        [self stopUpdating];
        [self startUpdating];
    }
}

- (void)setActiveScene:(XIScene *)scene
{
	if(scene == activeScene){return;}
	XIScene *oldScene = activeScene;
	[oldScene willResignActiveScene];
	[delegate gameWillChangeActiveSceneTo:scene];
	[scene willBecomeActiveScene];
	[oldScene release];
	activeScene = [scene retain];
	[scene didBecomeActiveScene];
	[delegate gameDidChangeActiveSceneTo:scene];
	[oldScene didResignActiveScene];
}

- (void)enableAccelerometer
{
	[self setupAccelerometer];
}

- (void)disableAccelerometer
{
	[[UIAccelerometer sharedAccelerometer] setDelegate:nil];
}

#pragma mark -
#pragma mark Acceletometer

// UIAccelerometerDelegate method, called when the device accelerates.
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
	if(activeScene && [activeScene respondsToSelector:@selector(accelerometer:didAccelerate:)])
	{
		[activeScene accelerometer:accelerometer didAccelerate:acceleration];
	}
}

#pragma mark -
#pragma mark Private methods

- (void)setupChipmunk
{
	cpInitChipmunk(); 
}

- (void)setupAccelerometer
{
	// Configure and start the accelerometer.
    [[UIAccelerometer sharedAccelerometer] setUpdateInterval:(1.0 / kAccelerometerFrequency)];
    [[UIAccelerometer sharedAccelerometer] setDelegate:self];
}

@end
